<template>
  <div class="defects-workspace">
    <header class="workspace-header">
      <div class="header-left">
        <div class="title-block">
          <h2>缺陷工作台</h2>
          <p class="subtitle">在一个位置管理、筛选、分析并协同处理所有缺陷</p>
        </div>
      </div>
      <div class="header-right">
        <div class="project-selector-wrapper">
          <label class="project-label">所属项目：</label>
          <el-select
            v-model="selectedProjectId"
            :placeholder="projects.length > 0 ? '请选择项目' : '暂无项目'"
            filterable
            class="project-selector"
            :clearable="false"
            :disabled="projects.length === 0"
            @change="handleProjectChange"
          >
            <el-option
              v-for="project in projects"
              :key="project.id"
              :label="project.name"
              :value="project.id"
            />
          </el-select>
        </div>
        <el-button 
          text
          class="refresh-button"
          @click="handleRefresh"
        >
          <el-icon><Refresh /></el-icon>
          刷新
        </el-button>
        <el-button 
          v-if="canCreate"
          type="primary" 
          class="create-button"
          :disabled="!selectedProjectId"
          @click="handleOpenCreate"
        >
          <el-icon><Plus /></el-icon>
          新建缺陷
        </el-button>
        <el-radio-group
          v-model="viewModeProxy"
          class="view-switcher"
        >
          <el-radio-button
            v-for="option in viewOptions"
            :key="option.value"
            :label="option.value"
          >
            {{ option.label }}
            </el-radio-button>
          </el-radio-group>
      </div>
    </header>

    <div class="workspace-main">
      <aside :class="['filter-panel', { 'is-collapsed': filterCollapsed }]">
        <header class="filter-header">
          <h3>筛选条件</h3>
          <el-button text size="small" class="collapse-btn" @click="toggleFilterCollapsed">
            <el-icon><DArrowLeft v-if="!filterCollapsed" /><DArrowRight v-else /></el-icon>
            </el-button>
        </header>
        <div class="filter-body" v-show="!filterCollapsed">
          <DefectFilterBar
            :filters="filters"
            :projects="projects"
            :users="users"
            :status-options="defectStatuses"
            :priority-options="priorityOptionsForFilter"
            :severity-options="severityOptionsForFilter"
            :type-options="typeOptionsForFilter"
            :source-options="sourceOptionsForFilter"
            :current-user-id="currentUserId"
            @apply="handleFilterApply"
            @reset="handleFilterReset"
          />
        </div>
      </aside>

      <section class="workspace-content">
        <main class="workspace-body">
          <!-- 初始加载状态 -->
          <PageLoading 
            v-if="initialLoading"
            :title="isRefreshing ? '正在刷新缺陷数据' : '正在加载缺陷数据'"
            :subtitle="isRefreshing ? '请稍候，正在更新数据...' : '请稍候，正在为您准备数据...'"
          />
          <transition v-else name="fade-slide" mode="out-in">
            <component
              :is="activeViewComponent"
              :key="`${viewMode}-${statusOptionsKey}`"
              :defects="defects"
              :loading="loading"
              :pagination="pagination"
              :status-options="statusOptionsForList"
              :priority-options="priorityOptionsForList"
              :severity-options="severityOptionsForList"
              :type-options="typeOptionsForList"
              :source-options="sourceOptionsForList"
              :users="userOptionsForList"
              :selected-ids="selectedIds"
              :batch-loading="batchLoading"
              :status-options-for-batch="defectStatuses"
              :priority-options-for-batch="priorityOptionsForFilter"
              :severity-options-for-batch="severityOptionsForFilter"
              :type-options-for-batch="typeOptionsForFilter"
              :source-options-for-batch="sourceOptionsForFilter"
              :users-for-batch="users"
              @page-change="handlePageChange"
              @page-size-change="handlePageSizeChange"
              @select-change="handleSelectionChange"
              @sort-change="handleSortChange"
              @open-detail="handleOpenDetail"
              @delete="handleDelete"
              @refresh="handleRefresh"
              @update-status="handleUpdateStatus"
              @update-priority="handleUpdatePriority"
              @update-severity="handleUpdateSeverity"
              @update-type="handleUpdateType"
              @update-source="handleUpdateSource"
              @update-assignee="handleUpdateAssignee"
              @update-reporter="handleUpdateReporter"
              @split-task="handleSplitTask"
              @create-defect="handleCreateDefectFromKanban"
              @open-edit="handleOpenEdit"
              @deleted="handleDefectDeleted"
              @batch-update-status="handleBatchUpdateStatus"
              @batch-update-priority="handleBatchUpdatePriority"
              @batch-update-severity="handleBatchUpdateSeverity"
              @batch-update-type="handleBatchUpdateType"
              @batch-update-source="handleBatchUpdateSource"
              @batch-assign="handleBatchAssign"
              @batch-update-reporter="handleBatchUpdateReporter"
              @batch-update-project="handleBatchUpdateProject"
              @batch-delete="handleBatchDelete"
              @batch-clear="handleClearSelection"
              @download-template="handleDownloadTemplate"
              @import="handleImportFile"
              @export="handleExportDefects"
            />
          </transition>
        </main>
      </section>
      </div>

    <!-- 创建缺陷对话框 -->
    <CreateDefect
      v-model:visible="createDialogVisible"
      :current-user-id="currentUserId"
      :default-project-id="filters.project_id"
      :default-status="quickCreateStatus"
      :projects="projects"
      :users="users"
      :type-options="typeOptionsForFilter"
      :severity-options="severityOptionsForFilter"
      :priority-options="priorityOptionsForFilter"
      :module-options="[]"
      :version-options="[]"
      @created="handleDefectCreated"
      @close="createDialogVisible = false"
    />

    <!-- 缺陷详情对话框 -->
    <DefectDetail
      v-if="detailDialogVisible && selectedDefectId"
      :visible="detailDialogVisible"
      :defect="selectedDefect"
      @update:visible="handleDetailDialogClose"
      @updated="handleDefectUpdated"
    />

    <!-- 任务创建对话框（用于任务拆分） -->
    <TaskCreateDialog
      v-model="taskSplitDialogVisible"
      :project-id="taskSplitDefect?.project_id || ''"
      :default-defect-id="taskSplitDefect?.id || ''"
      @success="handleTaskCreated"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, computed, watch } from 'vue'
import { useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, DArrowLeft, DArrowRight, Refresh } from '@element-plus/icons-vue'
import { h } from 'vue'
import { ElOption, ElSelect } from 'element-plus'
import { useDefectStates } from '@/composables/useDefectStates'
import { useDefectOptions } from '@/composables/useDefectOptions'
import { useUserStore } from '@/stores/user'
import { 
  getDefects, 
  getDefectById,
  deleteDefect,
  updateDefect,
  updateDefectStatus,
  updateDefectAssignee,
  batchUpdateDefects,
  batchDeleteDefects,
  exportDefects,
  importDefects,
  downloadDefectTemplate,
  type DefectBulkUpdate
} from '@/api/defect'
import { getProjects } from '@/api/project'
import { getProjectMembers } from '@/api/project'
import type { ProjectMember } from '@/types/project'
import { versionAPI, type VersionWithStats } from '@/api/version'
import { ResponseParser } from '@/utils/responseParser'
import type { Defect, DefectFilter } from '@/api/defect'
import type { ProjectResponse as Project } from '@/api/project'
import type { User } from '@/types/user'
import { DEFECT_TYPE_OPTIONS } from '@/types/defect'
import { ModuleType } from '@/types/state'
import { useStateStore } from '@/stores/state'
import DefectFilterBar from './components/DefectFilterBar.vue'
import DefectListView from './views/DefectListView.vue'
import DefectKanbanView from './views/DefectKanbanView.vue'
import CreateDefect from './components/CreateDefect.vue'
import DefectDetail from './components/DefectDetail.vue'
import TaskCreateDialog from '@/components/task/TaskCreateDialog.vue'
import PageLoading from '@/components/ui/PageLoading.vue'

// 状态管理
const { statusOptions: defectStatusOptions, loadStates: loadDefectStates } = useDefectStates()
const userStore = useUserStore()
const stateStore = useStateStore()
const route = useRoute()

// 响应式数据
const loading = ref(false)
const batchLoading = ref(false)
const viewMode = ref<'list' | 'kanban'>('list')
const filterCollapsed = ref(false)
const isInitialized = ref(false) // 标记是否已完成初始化
const initialLoading = ref(true)
const isRefreshing = ref(false)

// 用于强制更新看板视图的 key，当状态选项变化时更新
const statusOptionsKey = computed(() => {
  return defectStatusOptions.value.map(opt => `${opt.value}:${opt.label}`).join(',')
})

const currentUserId = computed(() => userStore.userInfo?.id ?? '')
const canCreate = computed(() => userStore.hasPermission?.('DEFECT_CREATE') ?? false)

const viewOptions = [
  { label: '列表', value: 'list', icon: 'List' },
  { label: '看板', value: 'kanban', icon: 'Grid' }
]

const viewComponentMap: Record<'list' | 'kanban', any> = {
  list: DefectListView,
  kanban: DefectKanbanView
}

const activeViewComponent = computed(() => viewComponentMap[viewMode.value] || DefectListView)

// 缺陷状态选项（用于筛选和批量操作）
const defectStatuses = computed(() => 
  defectStatusOptions.value.filter(status => !status.disabled)
)

// 缺陷状态选项（用于列表视图）
const statusOptionsForList = computed(() => 
  defectStatusOptions.value.filter(status => !status.disabled)
)

// 使用 composable 获取缺陷选项
const {
  formattedPriorityOptions: defectPriorityOptions,
  formattedSeverityOptions: defectSeverityOptions,
  formattedSourceOptions: defectSourceOptions,
  loadOptions: loadDefectOptions
} = useDefectOptions()

// 格式化优先级选项供列表视图使用
const priorityOptionsForList = computed(() => {
  return defectPriorityOptions.value.map((opt: any) => ({
    value: opt.value || opt.code,
    label: opt.label || opt.name
  }))
})

// 格式化优先级选项供筛选使用
const priorityOptionsForFilter = computed(() => {
  return defectPriorityOptions.value.map((opt: any) => ({
    value: opt.value || opt.code,
    label: opt.label || opt.name
  }))
})

// 格式化严重程度选项供列表视图使用
const severityOptionsForList = computed(() => {
  return defectSeverityOptions.value.map((opt: any) => ({
    value: opt.value || opt.code,
    label: opt.label || opt.name
  }))
})

// 格式化严重程度选项供筛选使用
const severityOptionsForFilter = computed(() => {
  return defectSeverityOptions.value.map((opt: any) => ({
    value: opt.value || opt.code,
    label: opt.label || opt.name
  }))
})

// 格式化缺陷类型选项
const typeOptionsForList = computed(() => {
  return DEFECT_TYPE_OPTIONS.map(opt => ({
    value: opt.value,
    label: opt.label
  }))
})

const typeOptionsForFilter = computed(() => {
  return DEFECT_TYPE_OPTIONS.map(opt => ({
    value: opt.value,
    label: opt.label
  }))
})

// 格式化缺陷来源选项
const sourceOptionsForFilter = computed(() => {
  return defectSourceOptions.value.map((opt: any) => ({
    value: opt.value || opt.code,
    label: opt.label || opt.name
  }))
})

// 格式化来源选项供列表视图使用
const sourceOptionsForList = computed(() => {
  return defectSourceOptions.value.map((opt: any) => ({
    value: opt.value || opt.code,
    label: opt.label || opt.name
  }))
})

// 格式化用户选项供列表视图使用（包含头像信息）
const userOptionsForList = computed(() => {
  return users.value.map(user => ({
    id: user.id,
    name: user.name || user.username || '',
    avatar: user.avatar
  }))
})

// 筛选条件
const filters = reactive<DefectFilter>({
  search: undefined,
  project_id: undefined,
  status: undefined,
  priority: undefined,
  severity: undefined,
  defect_type: undefined,
  source: undefined,
  assignee_id: undefined,
  reporter_id: undefined,
  found_date_start: undefined,
  found_date_end: undefined
})

// 分页
const pagination = reactive({
  page: 1,
  pageSize: 20,
  total: 0
})

// 排序
const sortConfig = reactive({
  prop: 'created_at' as string | undefined,
  order: 'descending' as 'ascending' | 'descending' | null
})

// 任务数据
const defects = ref<Defect[]>([])
const selectedIds = ref<string[]>([])

// 弹窗状态
const createDialogVisible = ref(false)
const quickCreateStatus = ref('')
const detailDialogVisible = ref(false)
const selectedDefectId = ref<string>('')
const selectedDefect = ref<Defect | null>(null)
const loadingDetail = ref(false)

// 任务拆分相关状态
const taskSplitDialogVisible = ref(false)
const taskSplitDefect = ref<{ id: string; project_id: string; title: string } | null>(null)

// 基础数据
const projects = ref<Project[]>([])
const users = ref<User[]>([])
const versions = ref<VersionWithStats[]>([])

// 选中的项目ID（从筛选条件中获取）
const selectedProjectId = computed({
  get: () => filters.project_id || '',
  set: (value: string) => {
    filters.project_id = value || undefined
  }
})

// 获取缺陷列表
const fetchDefects = async (isRefresh = false) => {
  if (isRefresh) {
    isRefreshing.value = true
    initialLoading.value = true
  }
  loading.value = true
  try {
    // 修复sort_order类型不匹配的问题
    let sort_order: 'asc' | 'desc' | undefined
    if (sortConfig.order === 'ascending') {
      sort_order = 'asc'
    } else if (sortConfig.order === 'descending') {
      sort_order = 'desc'
    } else {
      sort_order = undefined
    }
    
    // 构建查询参数，将所有筛选条件传递给API
    const params: DefectFilter = {
      page: pagination.page,
      size: pagination.pageSize,
      // 搜索关键词
      search: filters.search && filters.search.trim() ? filters.search.trim() : undefined,
      // 项目筛选
      project_id: filters.project_id || undefined,
      // 负责人筛选
      assignee_id: filters.assignee_id || undefined,
      // 报告人筛选
      reporter_id: filters.reporter_id || undefined,
      // 状态筛选
      status: filters.status || undefined,
      // 优先级筛选
      priority: filters.priority || undefined,
      // 严重程度筛选
      severity: filters.severity || undefined,
      // 缺陷类型筛选
      defect_type: filters.defect_type || undefined,
      // 缺陷来源筛选
      source: filters.source || undefined,
      // 日期范围筛选
      found_date_start: filters.found_date_start || undefined,
      found_date_end: filters.found_date_end || undefined,
      // 排序
      sort_by: sortConfig.prop || undefined,
      sort_order: sort_order
    }
    
    const response = await getDefects(params)
    const parsedResponse = ResponseParser.parseDefectListResponse(response)
    defects.value = parsedResponse.items
    pagination.total = parsedResponse.total
    
  } catch (error) {
    console.error('获取缺陷列表失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '获取缺陷列表失败'
    ElMessage.error(errorMessage)
  } finally {
    loading.value = false
    if (isRefresh) {
      setTimeout(() => {
        initialLoading.value = false
        isRefreshing.value = false
      }, 300)
    } else if (initialLoading.value) {
      initialLoading.value = false
    }
  }
}

// 获取基础数据
const fetchBaseData = async (forceRefresh = false) => {
  try {
    // 获取项目列表
    const projectsResponse = await getProjects({ page: 1, size: 100 })
    
    // 处理项目列表响应格式
    if (projectsResponse && projectsResponse.success) {
      const responseData = projectsResponse.data
      
      let projectsList: Project[] = []
      if (Array.isArray(responseData)) {
        projectsList = responseData
      } else if (responseData && Array.isArray((responseData as any).data)) {
        projectsList = (responseData as any).data
      } else if (responseData && Array.isArray((responseData as any).items)) {
        projectsList = (responseData as any).items
      }
      
      projects.value = projectsList
      
      // 如果项目列表加载完成且没有选择项目，默认选择第一个项目
      // 但在刷新时（forceRefresh=true），如果当前项目不在新列表中，需要重新选择
      if (projectsList.length > 0) {
        if (!filters.project_id) {
          // 没有选择项目，选择第一个
          const firstProject = projectsList[0]
          filters.project_id = firstProject.id
        } else if (forceRefresh) {
          // 刷新时，检查当前项目是否还在列表中
          const currentProjectExists = projectsList.some(p => p.id === filters.project_id)
          if (!currentProjectExists) {
            // 当前项目不存在，选择第一个项目
            const firstProject = projectsList[0]
            filters.project_id = firstProject.id
          }
        }
      }
    } else {
      projects.value = []
    }
    
    // 注意：不在这里调用 refreshUsers 和 fetchVersions，避免重复调用
    // 这些会在 onMounted 或 handleRefresh 中统一处理
  } catch (error) {
    console.error('获取基础数据失败:', error)
    ElMessage.error('获取基础数据失败')
  }
}

// 将项目成员转换为用户格式
const convertProjectMembersToUsers = (members: ProjectMember[]): User[] => {
  return members.map(member => ({
    id: member.user_id,
    username: member.username || member.user_name || '',
    name: member.name || member.username || member.user_name || '',
    email: member.email || member.user_email || '',
    avatar: member.avatar,
    roles: member.roles || (member.role ? [member.role] : []),
    status: 'active' as const,
    is_verified: false,
    created_at: member.joined_at,
    updated_at: member.joined_at
  }))
}

// 根据项目ID获取用户列表（项目成员）
const loadUsersByProject = async (projectId?: string): Promise<User[]> => {
  if (!projectId) {
    return []
  }

  try {
    const response = await getProjectMembers(projectId)
    if (response.success && response.data) {
      // 处理不同的响应格式
      let members: ProjectMember[] = []
      
      // getProjectMembers 返回 ApiResponse<ProjectMember[]>
      // 所以 response.data 应该是 ProjectMember[] 数组
      if (Array.isArray(response.data)) {
        // 如果 data 直接是数组
        members = response.data
      } else if (response.data && typeof response.data === 'object') {
        // 如果 data 是对象，可能是包装格式
        const dataObj = response.data as Record<string, any>
        if ('members' in dataObj && Array.isArray(dataObj.members)) {
          // 如果 data 是对象，包含 members 字段（实际后端返回格式）
          members = dataObj.members
        } else if (Array.isArray(dataObj)) {
          // 如果 dataObj 本身是数组（虽然不太可能，但为了类型安全）
          members = dataObj as ProjectMember[]
        }
      }
      
      return convertProjectMembersToUsers(members)
    }
    return []
  } catch (error) {
    console.error('获取项目成员失败:', error)
    return []
  }
}

// 获取版本列表（可按项目过滤）
const fetchVersions = async (projectId?: string) => {
  try {
    const params: Record<string, unknown> = { limit: 100 }
    if (projectId) {
      params.project_id = projectId
    }
    const versionsResponse = await versionAPI.getVersions(params)
    const parsedVersions = ResponseParser.parseListResponse<VersionWithStats>(versionsResponse)
    versions.value = parsedVersions.items
  } catch (error) {
    console.error('获取版本列表失败:', error)
    versions.value = []
  }
}

// 刷新用户列表（根据当前项目）- 只使用项目成员
const refreshUsers = async () => {
  const projectId = filters.project_id
  try {
    if (projectId) {
      // 如果已选择项目，获取项目成员
      users.value = await loadUsersByProject(projectId)
    } else {
      // 如果没有选择项目，清空用户列表
      users.value = []
    }
  } catch (error) {
    console.error('获取项目成员失败:', error)
    users.value = []
  }
}

// 事件处理
const handleFilterApply = async (newFilters: Partial<DefectFilter>) => {
  // 注意：项目ID的变化由 handleProjectChange 处理，这里不再处理项目ID
  // 明确更新所有筛选字段，包括 undefined 值（用于清除筛选）
  Object.keys(newFilters).forEach(key => {
    // 跳过 project_id，因为它由项目选择器单独处理
    if (key === 'project_id') {
      return
    }
    const value = newFilters[key as keyof DefectFilter]
    // 如果值是 undefined 或 null，用于清除筛选条件
    if (value === undefined || value === null) {
      (filters as any)[key] = undefined
    } else {
      (filters as any)[key] = value
    }
  })
  
  pagination.page = 1
  await fetchDefects()
}

const handleFilterReset = async () => {
  Object.assign(filters, {
    search: undefined,
    project_id: undefined,
    status: undefined,
    priority: undefined,
    severity: undefined,
    defect_type: undefined,
    source: undefined,
    assignee_id: undefined,
    reporter_id: undefined,
    found_date_start: undefined,
    found_date_end: undefined
  })
  pagination.page = 1
  await fetchDefects()
}

const handleOpenCreate = () => {
  if (!selectedProjectId.value) {
    ElMessage.warning('请先选择项目')
    return
  }
  quickCreateStatus.value = ''
  createDialogVisible.value = true
}

const handleCreateDefectFromKanban = (status: string) => {
  if (!selectedProjectId.value) {
    ElMessage.warning('请先选择项目')
    return
  }
  quickCreateStatus.value = status
  createDialogVisible.value = true
}

// 弹窗事件处理（已删除旧组件，待实现新组件）
const handleDefectCreated = () => {
  fetchDefects()
}

const handleDefectDeleted = () => {
  fetchDefects()
  // 如果删除的是当前打开的缺陷，关闭详情弹窗
  if (selectedDefectId.value && selectedDefect.value?.id === selectedDefectId.value) {
    detailDialogVisible.value = false
    selectedDefect.value = null
    selectedDefectId.value = ''
  }
}

// 处理详情弹窗关闭
const handleDetailDialogClose = (visible: boolean) => {
  detailDialogVisible.value = visible
  if (!visible) {
    // 延迟清空数据，确保组件完全卸载后再清空
    setTimeout(() => {
      selectedDefect.value = null
      selectedDefectId.value = ''
    }, 100)
  }
}

// 处理缺陷更新
const handleDefectUpdated = async (defectId: string) => {
  // 刷新缺陷列表
  await fetchDefects()
  // 如果更新的是当前打开的缺陷，刷新详情
  if (selectedDefectId.value === defectId) {
    await fetchDefectDetail(defectId)
  }
}

const handleSelectionChange = (ids: string[]) => {
  selectedIds.value = ids
}

// 获取缺陷详情
const fetchDefectDetail = async (id: string) => {
  if (!id) return
  
  loadingDetail.value = true
  try {
    const response = await getDefectById(id)
    console.log('缺陷详情API响应:', response)
    
    // 处理不同的响应格式
    if (response && typeof response === 'object') {
      // 如果响应有 success 字段
      if ('success' in response) {
        const apiResponse = response as { success: boolean; data?: Defect; message?: string }
        if (apiResponse.success && apiResponse.data) {
          selectedDefect.value = apiResponse.data
        } else {
          const errorMessage = apiResponse.message || '获取缺陷详情失败'
          ElMessage.error(errorMessage)
          return
        }
      } 
      // 如果响应直接是数据对象
      else if ('id' in response) {
        selectedDefect.value = response as Defect
      }
      // 如果响应有 data 字段
      else if ('data' in response && (response as any).data) {
        selectedDefect.value = (response as any).data
      }
      else {
        ElMessage.error('获取缺陷详情失败：响应格式不正确')
        return
      }
    } else {
      ElMessage.error('获取缺陷详情失败：无效的响应')
      return
    }
  } catch (error: any) {
    console.error('获取缺陷详情失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '获取缺陷详情失败'
    ElMessage.error(errorMessage)
  } finally {
    loadingDetail.value = false
  }
}

const handleOpenDetail = async (id: string) => {
  selectedDefectId.value = id
  detailDialogVisible.value = true
  // 先显示对话框，再加载数据，避免组件被销毁
  await fetchDefectDetail(id)
}

// 处理打开编辑（从看板视图触发）
const handleOpenEdit = async (id: string) => {
  selectedDefectId.value = id
  detailDialogVisible.value = true
  // 先显示对话框，再加载数据，避免组件被销毁
  await fetchDefectDetail(id)
}

const handleDelete = async (id: string) => {
  try {
    await ElMessageBox.confirm(
      '确定要删除该缺陷吗？删除后无法恢复。',
      '确认删除',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }
    )
    
    const response = await deleteDefect(id)
    if (ResponseParser.isSuccess(response)) {
      ElMessage.success('删除成功')
      // 刷新缺陷列表
      await fetchDefects()
    } else {
      const errorMessage = ResponseParser.extractMessage(response) || '删除失败'
      ElMessage.error(errorMessage)
    }
  } catch (error: any) {
    if (error !== 'cancel') {
      console.error('删除缺陷失败:', error)
      const errorMessage = ResponseParser.extractMessage(error) || '删除缺陷失败'
      ElMessage.error(errorMessage)
    }
  }
}

// 项目变化处理
const handleProjectChange = async (projectId: string) => {
  if (projectId) {
    // 刷新用户列表（项目成员）
    await refreshUsers()
    // 刷新版本列表
    await fetchVersions(projectId)
    // 刷新缺陷列表
    await fetchDefects()
  } else {
    // 如果清空项目，清空用户列表和缺陷列表
    users.value = []
    versions.value = []
    defects.value = []
  }
}

const handleRefresh = async () => {
  try {
    // 标记为刷新状态并显示加载状态
    isRefreshing.value = true
    initialLoading.value = true
    
    // 先刷新基础数据（项目列表、缺陷选项）
    await fetchBaseData(true)
    
    // 然后刷新项目相关数据和缺陷数据
    const refreshPromises: Promise<any>[] = [
      // 刷新缺陷列表
      fetchDefects(true)
    ]
    
    // 如果已选择项目，刷新项目相关数据（成员、版本）
    if (filters.project_id) {
      refreshPromises.push(
        refreshUsers(),
        fetchVersions(filters.project_id)
      )
    }
    
    // 并行执行所有刷新操作
    await Promise.all(refreshPromises)
    
    ElMessage.success('刷新成功')
  } catch (error) {
    console.error('刷新失败:', error)
    ElMessage.error('刷新失败，请稍后重试')
  } finally {
    // 延迟一点隐藏加载状态，让动画更自然
    setTimeout(() => {
      initialLoading.value = false
      isRefreshing.value = false
    }, 300)
  }
}

const handleUpdateStatus = async (id: string, status: string) => {
  if (!id || !status) return
  try {
    const response = await updateDefectStatus(id, status as any)
    // updateDefectStatus 返回的是 ApiResponse<Defect>，格式为 { success: true, data: {...}, message: '...' }
    if (response?.success !== false) {
      // 立即更新列表中的对应项，避免重新获取整个列表
      const defectIndex = defects.value.findIndex(d => d.id === id)
      if (defectIndex !== -1 && response?.data) {
        defects.value[defectIndex] = { ...defects.value[defectIndex], status: (response.data as any).status || status }
      } else {
        // 如果找不到对应项或没有返回数据，则重新获取列表
        await fetchDefects()
      }
      // 拖拽更新状态时，不显示成功提示，避免打断用户操作流程
      // 只在非拖拽场景显示成功提示
    } else {
      const errorMessage = response?.message || ResponseParser.extractMessage(response) || '状态更新失败'
      ElMessage.error(errorMessage)
    }
  } catch (error) {
    console.error('更新状态失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '更新状态失败'
    ElMessage.error(errorMessage)
  }
}

const handleUpdatePriority = async (id: string, priority: string) => {
  if (!id || !priority) return
  try {
    const response = await updateDefect(id, { priority } as any)
    // updateDefect 返回的是 ApiResponse<Defect>，格式为 { success: true, data: {...}, message: '...' }
    if (response?.success !== false) {
      // 立即更新列表中的对应项，避免重新获取整个列表
      const defectIndex = defects.value.findIndex(d => d.id === id)
      if (defectIndex !== -1 && response?.data) {
        defects.value[defectIndex] = { ...defects.value[defectIndex], priority: (response.data as any).priority || priority }
      } else {
        // 如果找不到对应项或没有返回数据，则重新获取列表
        await fetchDefects()
      }
      ElMessage.success('优先级更新成功')
    } else {
      const errorMessage = response?.message || ResponseParser.extractMessage(response) || '优先级更新失败'
      ElMessage.error(errorMessage)
    }
  } catch (error) {
    console.error('更新优先级失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '更新优先级失败'
    ElMessage.error(errorMessage)
  }
}

const handleUpdateSeverity = async (id: string, severity: string) => {
  if (!id || !severity) return
  try {
    const response = await updateDefect(id, { severity } as any)
    // updateDefect 返回的是 ApiResponse<Defect>，格式为 { success: true, data: {...}, message: '...' }
    if (response?.success !== false) {
      // 立即更新列表中的对应项，避免重新获取整个列表
      const defectIndex = defects.value.findIndex(d => d.id === id)
      if (defectIndex !== -1 && response?.data) {
        defects.value[defectIndex] = { ...defects.value[defectIndex], severity: (response.data as any).severity || severity }
      } else {
        // 如果找不到对应项或没有返回数据，则重新获取列表
        await fetchDefects()
      }
      ElMessage.success('严重程度更新成功')
    } else {
      const errorMessage = response?.message || ResponseParser.extractMessage(response) || '严重程度更新失败'
      ElMessage.error(errorMessage)
    }
  } catch (error) {
    console.error('更新严重程度失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '更新严重程度失败'
    ElMessage.error(errorMessage)
  }
}

const handleUpdateType = async (id: string, type: string) => {
  if (!id || !type) return
  try {
    const response = await updateDefect(id, { type: type as any } as any)
    if (response?.success !== false) {
      const defectIndex = defects.value.findIndex(d => d.id === id)
      if (defectIndex !== -1 && response?.data) {
        defects.value[defectIndex] = { ...defects.value[defectIndex], type: (response.data as any).type || type }
      } else {
        await fetchDefects()
      }
      ElMessage.success('类型更新成功')
    } else {
      const errorMessage = response?.message || ResponseParser.extractMessage(response) || '类型更新失败'
      ElMessage.error(errorMessage)
    }
  } catch (error) {
    console.error('更新类型失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '更新类型失败'
    ElMessage.error(errorMessage)
  }
}

const handleUpdateSource = async (id: string, source: string) => {
  if (!id || !source) return
  try {
    const response = await updateDefect(id, { source: source as any } as any)
    if (response?.success !== false) {
      const defectIndex = defects.value.findIndex(d => d.id === id)
      if (defectIndex !== -1 && response?.data) {
        defects.value[defectIndex] = { ...defects.value[defectIndex], source: (response.data as any).source || source }
      } else {
        await fetchDefects()
      }
      ElMessage.success('来源更新成功')
    } else {
      const errorMessage = response?.message || ResponseParser.extractMessage(response) || '来源更新失败'
      ElMessage.error(errorMessage)
    }
  } catch (error) {
    console.error('更新来源失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '更新来源失败'
    ElMessage.error(errorMessage)
  }
}

const handleUpdateAssignee = async (id: string, assigneeId: string | null) => {
  if (!id) return
  try {
    // 如果 assigneeId 是 null，传递 undefined 以便后端正确处理取消分配
    const response = await updateDefectAssignee(id, assigneeId || undefined)
    // updateDefectAssignee 返回的是 ApiResponse<Defect>，格式为 { success: true, data: {...}, message: '...' }
    if (response?.success !== false) {
      // 立即更新列表中的对应项，避免重新获取整个列表
      const defectIndex = defects.value.findIndex(d => d.id === id)
      if (defectIndex !== -1 && response?.data) {
        const updatedDefect = response.data as any
        defects.value[defectIndex] = { 
          ...defects.value[defectIndex], 
          assignee_id: updatedDefect.assignee_id || assigneeId,
          assignee_name: updatedDefect.assignee_name || undefined
        }
      } else {
        // 如果找不到对应项或没有返回数据，则重新获取列表
        await fetchDefects()
      }
      ElMessage.success('负责人更新成功')
    } else {
      const errorMessage = response?.message || ResponseParser.extractMessage(response) || '负责人更新失败'
      ElMessage.error(errorMessage)
    }
  } catch (error) {
    console.error('更新负责人失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '更新负责人失败'
    ElMessage.error(errorMessage)
  }
}

const handleUpdateReporter = async (id: string, reporterId: string | null) => {
  if (!id) return
  try {
    const response = await updateDefect(id, { reporter_id: reporterId || undefined } as any)
    if (response?.success !== false) {
      const defectIndex = defects.value.findIndex(d => d.id === id)
      if (defectIndex !== -1 && response?.data) {
        const updatedDefect = response.data as any
        defects.value[defectIndex] = { 
          ...defects.value[defectIndex], 
          reporter_id: updatedDefect.reporter_id || reporterId,
          reporter_name: updatedDefect.reporter_name || undefined
        }
      } else {
        await fetchDefects()
      }
      ElMessage.success('报告人更新成功')
    } else {
      const errorMessage = response?.message || ResponseParser.extractMessage(response) || '报告人更新失败'
      ElMessage.error(errorMessage)
    }
  } catch (error) {
    console.error('更新报告人失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '更新报告人失败'
    ElMessage.error(errorMessage)
  }
}

// 处理任务拆分
const handleSplitTask = (defect: any) => {
  if (!defect || !defect.id) {
    ElMessage.warning('无法识别缺陷信息')
    return
  }
  
  taskSplitDefect.value = {
    id: defect.id,
    project_id: defect.project_id || '',
    title: defect.title || ''
  }
  taskSplitDialogVisible.value = true
}

// 任务创建成功后的处理
const handleTaskCreated = async () => {
  taskSplitDefect.value = null
  taskSplitDialogVisible.value = false
  await fetchDefects()
}

const handlePageChange = async (page: number) => {
  pagination.page = page
  await fetchDefects()
}

const handlePageSizeChange = async (size: number) => {
  pagination.pageSize = size
  pagination.page = 1
  await fetchDefects()
}

const handleSortChange = async ({ prop, order }: { prop: string; order: 'ascending' | 'descending' | null }) => {
  sortConfig.prop = prop
  sortConfig.order = order
  pagination.page = 1  // 排序时重置到第一页
  await fetchDefects()
}

const toggleFilterCollapsed = () => {
  filterCollapsed.value = !filterCollapsed.value
}

const viewModeProxy = computed({
  get: () => viewMode.value,
  set: (value) => {
    viewMode.value = value as 'list' | 'kanban'
  }
})

// 监听状态 store 中缺陷模块的状态变化，自动刷新状态列表
watch(
  () => stateStore.getStatesByModule(ModuleType.DEFECT),
  async (newStates, oldStates) => {
    // 如果还未初始化完成，不处理 watch 触发（避免初始化时的重复调用）
    if (!isInitialized.value) {
      return
    }
    
    // 如果 oldStates 为空或 undefined，且 newStates 有数据，可能是首次加载，不触发重新加载
    if ((!oldStates || oldStates.length === 0) && newStates.length > 0) {
      return
    }
    
    // 如果状态列表发生变化（长度变化或状态被启用/禁用），重新加载状态
    if (!oldStates || newStates.length !== oldStates.length) {
      // 状态数量变化，清除缓存并重新加载
      stateStore.clearModuleCache(ModuleType.DEFECT)
      await loadDefectStates()
      return
    }
    
    // 检查是否有状态的 is_enabled 或 is_visible 发生变化
    const hasStateChanged = newStates.some((newState) => {
      const oldState = oldStates.find(s => s.id === newState.id)
      if (!oldState) return true
      return (
        oldState.is_enabled !== newState.is_enabled ||
        oldState.is_visible !== newState.is_visible ||
        oldState.code !== newState.code ||
        oldState.name !== newState.name ||
        oldState.color !== newState.color
      )
    })
    
    if (hasStateChanged) {
      // 状态属性变化，清除缓存并重新加载状态
      stateStore.clearModuleCache(ModuleType.DEFECT)
      await loadDefectStates()
    }
  },
  { deep: true, immediate: false }
)

// 批量操作相关函数
const ensureSelection = () => {
  if (!selectedIds.value.length) {
    ElMessage.warning('请先选择缺陷')
    return false
  }
  return true
}

const promptSelect = async (options: Array<{ value: string; label: string }>, title: string, placeholder: string) => {
  const selected = ref(options[0]?.value ?? '')

  try {
    await ElMessageBox({
      title: title,
      message: h(
        'div',
        { class: 'prompt-select-wrapper' },
        [
          h('div', { class: 'select-hint' }, `已选择 ${selectedIds.value.length} 项缺陷`),
          h('div', { class: 'select-label' }, '请选择要设置的值：'),
          h(
            ElSelect,
            {
              modelValue: selected.value,
              placeholder,
              style: 'width: 100%;',
              size: 'large',
              filterable: options.length > 5,
              'onUpdate:modelValue': (value: string) => {
                selected.value = value
              }
            },
            () =>
              options.map(option =>
                h(ElOption, {
                  key: option.value,
                  label: option.label,
                  value: option.value
                })
              )
          )
        ]
      ),
      showCancelButton: true,
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      customClass: 'batch-operation-dialog',
      beforeClose: (action, _instance, done) => {
        if (action === 'confirm') {
          if (!selected.value) {
            ElMessage.warning('请选择一个值')
            return
          }
          done()
        } else {
          done()
        }
      }
    })
    return selected.value
  } catch {
    return null
  }
}

const handleClearSelection = () => {
  selectedIds.value = []
}

const handleBatchUpdateStatus = async () => {
  if (!ensureSelection()) return
  if (!selectedProjectId.value) {
    ElMessage.warning('请先选择项目')
    return
  }
  
  const statusValue = await promptSelect(defectStatuses.value, '批量更新状态', '请选择状态')
  if (!statusValue) return

  batchLoading.value = true
  try {
    const payload: DefectBulkUpdate = {
      defect_ids: selectedIds.value.slice(),
      status: statusValue as any
    }
    const response = await batchUpdateDefects(payload)
    if (ResponseParser.isSuccess(response)) {
      ElMessage.success('批量更新状态成功')
      await fetchDefects()
      handleClearSelection()
    } else {
      ElMessage.error(ResponseParser.extractMessage(response) || '批量更新状态失败')
    }
  } catch (error) {
    console.error('批量更新状态失败', error)
    ElMessage.error('批量更新状态失败，请稍后重试')
  } finally {
    batchLoading.value = false
  }
}

const handleBatchUpdatePriority = async () => {
  if (!ensureSelection()) return
  if (!selectedProjectId.value) {
    ElMessage.warning('请先选择项目')
    return
  }
  
  const priorityValue = await promptSelect(priorityOptionsForFilter.value, '批量更新优先级', '请选择优先级')
  if (!priorityValue) return

  batchLoading.value = true
  try {
    const payload: DefectBulkUpdate = {
      defect_ids: selectedIds.value.slice(),
      priority: priorityValue as any
    }
    const response = await batchUpdateDefects(payload)
    if (ResponseParser.isSuccess(response)) {
      ElMessage.success('批量更新优先级成功')
      await fetchDefects()
      handleClearSelection()
    } else {
      ElMessage.error(ResponseParser.extractMessage(response) || '批量更新优先级失败')
    }
  } catch (error) {
    console.error('批量更新优先级失败', error)
    ElMessage.error('批量更新优先级失败，请稍后重试')
  } finally {
    batchLoading.value = false
  }
}

const handleBatchUpdateSeverity = async () => {
  if (!ensureSelection()) return
  
  const severityValue = await promptSelect(severityOptionsForFilter.value, '批量更新严重程度', '请选择严重程度')
  if (!severityValue) return

  batchLoading.value = true
  try {
    const payload: DefectBulkUpdate = {
      defect_ids: selectedIds.value.slice(),
      severity: severityValue as any
    }
    const response = await batchUpdateDefects(payload)
    if (ResponseParser.isSuccess(response)) {
      ElMessage.success('批量更新严重程度成功')
      await fetchDefects()
      handleClearSelection()
    } else {
      ElMessage.error(ResponseParser.extractMessage(response) || '批量更新严重程度失败')
    }
  } catch (error) {
    console.error('批量更新严重程度失败', error)
    ElMessage.error('批量更新严重程度失败，请稍后重试')
  } finally {
    batchLoading.value = false
  }
}

const handleBatchUpdateType = async () => {
  if (!ensureSelection()) return
  
  const typeValue = await promptSelect(typeOptionsForFilter.value, '批量更新缺陷类型', '请选择缺陷类型')
  if (!typeValue) return

  batchLoading.value = true
  try {
    const payload: DefectBulkUpdate = {
      defect_ids: selectedIds.value.slice(),
      type: typeValue as any
    }
    const response = await batchUpdateDefects(payload)
    if (ResponseParser.isSuccess(response)) {
      ElMessage.success('批量更新缺陷类型成功')
      await fetchDefects()
      handleClearSelection()
    } else {
      ElMessage.error(ResponseParser.extractMessage(response) || '批量更新缺陷类型失败')
    }
  } catch (error) {
    console.error('批量更新缺陷类型失败', error)
    ElMessage.error('批量更新缺陷类型失败，请稍后重试')
  } finally {
    batchLoading.value = false
  }
}

const handleBatchUpdateSource = async () => {
  if (!ensureSelection()) return
  
  const sourceValue = await promptSelect(sourceOptionsForFilter.value, '批量更新缺陷来源', '请选择缺陷来源')
  if (!sourceValue) return

  batchLoading.value = true
  try {
    const payload: DefectBulkUpdate = {
      defect_ids: selectedIds.value.slice(),
      source: sourceValue as any
    }
    const response = await batchUpdateDefects(payload)
    if (ResponseParser.isSuccess(response)) {
      ElMessage.success('批量更新缺陷来源成功')
      await fetchDefects()
      handleClearSelection()
    } else {
      ElMessage.error(ResponseParser.extractMessage(response) || '批量更新缺陷来源失败')
    }
  } catch (error) {
    console.error('批量更新缺陷来源失败', error)
    ElMessage.error('批量更新缺陷来源失败，请稍后重试')
  } finally {
    batchLoading.value = false
  }
}

const handleBatchAssign = async () => {
  if (!ensureSelection()) return
  if (!selectedProjectId.value) {
    ElMessage.warning('请先选择项目')
    return
  }
  if (users.value.length === 0) {
    ElMessage.warning('当前项目暂无成员，无法分配负责人')
    return
  }
  
  const assigneeValue = await promptSelect(
    users.value.map(u => ({ value: u.id, label: u.name })),
    '批量分配负责人',
    '请选择负责人'
  )
  if (!assigneeValue) return

  batchLoading.value = true
  try {
    const payload: DefectBulkUpdate = {
      defect_ids: selectedIds.value.slice(),
      assignee_id: assigneeValue
    }
    const response = await batchUpdateDefects(payload)
    if (ResponseParser.isSuccess(response)) {
      ElMessage.success('批量分配成功')
      await fetchDefects()
      handleClearSelection()
    } else {
      ElMessage.error(ResponseParser.extractMessage(response) || '批量分配失败')
    }
  } catch (error) {
    console.error('批量分配失败', error)
    ElMessage.error('批量分配失败，请稍后重试')
  } finally {
    batchLoading.value = false
  }
}

const handleBatchUpdateReporter = async () => {
  if (!ensureSelection()) return
  
  const reporterValue = await promptSelect(
    users.value.map(u => ({ value: u.id, label: u.name })),
    '批量更新报告人',
    '请选择报告人'
  )
  if (!reporterValue) return

  batchLoading.value = true
  try {
    const payload: DefectBulkUpdate = {
      defect_ids: selectedIds.value.slice(),
      reporter_id: reporterValue
    }
    const response = await batchUpdateDefects(payload)
    if (ResponseParser.isSuccess(response)) {
      ElMessage.success('批量更新报告人成功')
      await fetchDefects()
      handleClearSelection()
    } else {
      ElMessage.error(ResponseParser.extractMessage(response) || '批量更新报告人失败')
    }
  } catch (error) {
    console.error('批量更新报告人失败', error)
    ElMessage.error('批量更新报告人失败，请稍后重试')
  } finally {
    batchLoading.value = false
  }
}

const handleBatchUpdateProject = async () => {
  if (!ensureSelection()) return
  
  const projectValue = await promptSelect(
    projects.value.map(p => ({ value: p.id, label: p.name })),
    '批量更新所属项目',
    '请选择项目'
  )
  if (!projectValue) return

  batchLoading.value = true
  try {
    const payload: DefectBulkUpdate = {
      defect_ids: selectedIds.value.slice(),
      project_id: projectValue
    }
    const response = await batchUpdateDefects(payload)
    if (ResponseParser.isSuccess(response)) {
      ElMessage.success('批量更新所属项目成功')
      await fetchDefects()
      handleClearSelection()
    } else {
      ElMessage.error(ResponseParser.extractMessage(response) || '批量更新所属项目失败')
    }
  } catch (error) {
    console.error('批量更新所属项目失败', error)
    ElMessage.error('批量更新所属项目失败，请稍后重试')
  } finally {
    batchLoading.value = false
  }
}

const handleBatchDelete = async () => {
  if (!ensureSelection()) return
  
  try {
    await ElMessageBox.confirm(
      `确定要删除选中的 ${selectedIds.value.length} 项缺陷吗？删除后无法恢复。`,
      '批量删除确认',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }
    )
  } catch {
    return
  }

  batchLoading.value = true
  try {
    const response = await batchDeleteDefects(selectedIds.value.slice())
    if (ResponseParser.isSuccess(response)) {
      ElMessage.success('批量删除成功')
      await fetchDefects()
      handleClearSelection()
    } else {
      ElMessage.error(ResponseParser.extractMessage(response) || '批量删除失败')
    }
  } catch (error) {
    console.error('批量删除失败', error)
    ElMessage.error('批量删除失败，请稍后重试')
  } finally {
    batchLoading.value = false
  }
}

// 导入导出相关函数
const handleDownloadTemplate = async () => {
  try {
    batchLoading.value = true
    const response = await downloadDefectTemplate()
    
    // 处理文件下载
    const blob = new Blob([response.data], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    })
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    
    // 从响应头获取文件名，或使用默认文件名
    const contentDisposition = response.headers['content-disposition'] || response.headers['Content-Disposition']
    let filename = `缺陷导入模板_${new Date().getTime()}.xlsx`
    if (contentDisposition) {
      // 优先匹配 RFC 5987 格式：filename*=UTF-8''<encoded>
      const rfc5987Match = contentDisposition.match(/filename\*=UTF-8''([^;]+)/i)
      if (rfc5987Match && rfc5987Match[1]) {
        try {
          filename = decodeURIComponent(rfc5987Match[1])
        } catch {
          filename = rfc5987Match[1]
        }
      } else {
        // 回退到标准格式：filename="..." 或 filename=...
        const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
        if (filenameMatch && filenameMatch[1]) {
          filename = filenameMatch[1].replace(/['"]/g, '')
          try {
            filename = decodeURIComponent(filename)
          } catch {
            // 如果解码失败，使用原始文件名
          }
        }
      }
    }
    
    link.download = filename
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)
    
    ElMessage.success('模板下载成功')
  } catch (error) {
    console.error('下载模板失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '下载模板失败'
    ElMessage.error(errorMessage)
  } finally {
    batchLoading.value = false
  }
}

const handleImportFile = async (file: any) => {
  try {
    batchLoading.value = true
    
    const fileType = file.raw.type
    const fileName = file.name
    const validTypes = [
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      'application/vnd.ms-excel'
    ]
    
    if (!validTypes.includes(fileType) && !fileName.endsWith('.xlsx') && !fileName.endsWith('.xls')) {
      ElMessage.error('只支持 Excel 文件 (.xlsx, .xls)')
      batchLoading.value = false
      return
    }

    await ElMessageBox.confirm(
      `确定要导入文件 "${fileName}" 吗？\n导入前请确保文件格式正确，包含必需的列（标题、项目）。`,
      '确认导入',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }
    )
    
    const response = await importDefects(file.raw)
    const parsedResponse = ResponseParser.parseResponse(response)
    
    if (parsedResponse.success) {
      const data = parsedResponse.data as any
      const successCount = data?.success_count || 0
      const errorCount = data?.error_count || 0
      const errors = data?.errors || []
      
      let message = `导入完成: 成功 ${successCount} 条`
      if (errorCount > 0) {
        message += `, 失败 ${errorCount} 条`
        
        const errorPreview = errors.slice(0, 10).join('\n')
        const moreErrors = errors.length > 10 ? `\n... 还有 ${errors.length - 10} 个错误` : ''
        
        ElMessageBox.alert(
          `${message}\n\n错误详情:\n${errorPreview}${moreErrors}`,
          '导入结果',
          {
            confirmButtonText: '确定',
            type: errorCount > 0 ? 'warning' : 'success',
            dangerouslyUseHTMLString: false
          }
        )
      } else {
        ElMessage.success(message)
      }
      
      await fetchDefects()
    } else {
      ElMessage.error(parsedResponse.message || '导入失败')
    }
  } catch (error: any) {
    if (error !== 'cancel') {
      console.error('导入缺陷失败:', error)
      const errorMessage = ResponseParser.extractMessage(error) || '导入缺陷失败'
      ElMessage.error(errorMessage)
    }
  } finally {
    batchLoading.value = false
  }
}

const handleExportDefects = async () => {
  try {
    batchLoading.value = true
    
    const exportParams: any = {}
    
    if (selectedIds.value && selectedIds.value.length > 0) {
      exportParams.defect_ids = selectedIds.value.join(',')
    } else {
      if (filters.search && filters.search.trim()) {
        exportParams.search = filters.search.trim()
      }
      if (filters.project_id && filters.project_id.trim()) {
        exportParams.project_id = filters.project_id.trim()
      }
      if (filters.assignee_id && filters.assignee_id.trim()) {
        exportParams.assignee_id = filters.assignee_id.trim()
      }
      if (filters.reporter_id && filters.reporter_id.trim()) {
        exportParams.reporter_id = filters.reporter_id.trim()
      }
      if (filters.status) {
        exportParams.status = filters.status
      }
      if (filters.priority) {
        exportParams.priority = filters.priority
      }
      if (filters.severity) {
        exportParams.severity = filters.severity
      }
      if (filters.defect_type) {
        exportParams.defect_type = filters.defect_type
      }
      if (filters.source) {
        exportParams.source = filters.source
      }
      if (filters.found_date_start) {
        exportParams.found_date_start = filters.found_date_start
      }
      if (filters.found_date_end) {
        exportParams.found_date_end = filters.found_date_end
      }
    }
    
    const response = await exportDefects(exportParams)
    
    const blob = new Blob([response.data], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    })
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    
    // 从响应头获取文件名，或使用默认文件名
    const contentDisposition = response.headers['content-disposition'] || response.headers['Content-Disposition']
    let filename = `缺陷导出_${new Date().getTime()}.xlsx`
    if (contentDisposition) {
      // 优先匹配 RFC 5987 格式：filename*=UTF-8''<encoded>
      const rfc5987Match = contentDisposition.match(/filename\*=UTF-8''([^;]+)/i)
      if (rfc5987Match && rfc5987Match[1]) {
        try {
          filename = decodeURIComponent(rfc5987Match[1])
        } catch {
          filename = rfc5987Match[1]
        }
      } else {
        // 回退到标准格式：filename="..." 或 filename=...
        const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
        if (filenameMatch && filenameMatch[1]) {
          filename = filenameMatch[1].replace(/['"]/g, '')
          try {
            filename = decodeURIComponent(filename)
          } catch {
            // 如果解码失败，使用原始文件名
          }
        }
      }
    }
    
    link.download = filename
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)
    
    if (selectedIds.value && selectedIds.value.length > 0) {
      ElMessage.success(`导出成功：已导出 ${selectedIds.value.length} 项选中的缺陷`)
    } else {
      ElMessage.success('导出成功：已导出全部缺陷数据')
    }
  } catch (error) {
    console.error('导出缺陷失败:', error)
    const errorMessage = ResponseParser.extractMessage(error) || '导出缺陷失败'
    ElMessage.error(errorMessage)
  } finally {
    batchLoading.value = false
  }
}

// 监听项目变化，更新版本列表和用户列表
// 使用 immediate: false 避免初始化时触发
watch(() => filters.project_id, async (newProjectId, oldProjectId) => {
  // 如果项目变化（且不是初始化时的第一次设置），重置并刷新数据
  if (newProjectId !== oldProjectId && oldProjectId !== undefined) {
    // 刷新用户列表（项目成员）
    await refreshUsers()
    // 刷新版本列表
    await fetchVersions(newProjectId || undefined)
  }
}, { immediate: false })

// 初始化
onMounted(async () => {
  try {
    // 初始化状态数据 - 使用composable
    await loadDefectStates()
    await loadDefectOptions()
    
    // 检查 URL 参数，如果有 project_id，设置筛选并自动打开创建对话框
    const projectId = route.query.project_id as string
    if (projectId) {
      filters.project_id = projectId
      // 延迟打开对话框，确保数据已加载
      setTimeout(() => {
        createDialogVisible.value = true
      }, 500)
    }
    
    // 获取基础数据（包括项目列表）
    await fetchBaseData()
    
    // 确保有项目被选中（如果项目列表已加载但还没有选择项目）
    if (!filters.project_id && projects.value.length > 0) {
      const firstProject = projects.value[0]
      filters.project_id = firstProject.id
    }
    
    // 如果已选择项目，加载项目相关的数据（成员和版本）
    if (filters.project_id) {
      await Promise.all([
        refreshUsers(),
        fetchVersions(filters.project_id)
      ])
    }
    
    // 加载缺陷列表
    await fetchDefects()
    
    // 标记初始化完成，允许 watch 监听后续的状态变化
    isInitialized.value = true
  } catch (error) {
    console.error('加载缺陷数据失败:', error)
    ElMessage.error('加载数据失败，请稍后重试')
  } finally {
    initialLoading.value = false
  }
})

</script>

<style scoped lang="scss">
.prompt-select-wrapper {
  padding-top: 8px;
  
  .select-hint {
    font-size: 13px;
    color: #909399;
    margin-bottom: 16px;
    padding: 8px 12px;
    background: #f0f9ff;
    border-left: 3px solid #409eff;
    border-radius: 4px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    
    &::before {
      content: '';
      display: inline-block;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: #409eff;
    }
  }
  
  .select-label {
    font-size: 14px;
    color: #606266;
    margin-bottom: 12px;
    font-weight: 500;
  }
}
</style>

<style lang="scss">
/* 批量操作弹窗全局样式 */
.batch-operation-dialog {
  border-radius: 12px;
  overflow: hidden;
  width: 480px;
}

.batch-operation-dialog .el-message-box__header {
  padding: 20px 24px 16px;
  border-bottom: 1px solid #ebeef5;
  background: linear-gradient(135deg, #f8fbff 0%, #ffffff 100%);
}

.batch-operation-dialog .el-message-box__title {
  font-size: 18px;
  font-weight: 600;
  color: #303133;
  line-height: 1.4;
}

.batch-operation-dialog .el-message-box__headerbtn {
  top: 20px;
  right: 20px;
}

.batch-operation-dialog .el-message-box__headerbtn .el-message-box__close {
  color: #909399;
  font-size: 18px;
}

.batch-operation-dialog .el-message-box__headerbtn .el-message-box__close:hover {
  color: #606266;
}

.batch-operation-dialog .el-message-box__content {
  padding: 24px;
  background: #ffffff;
}

.batch-operation-dialog .el-message-box__message {
  margin: 0;
  padding: 0;
}

.batch-operation-dialog .el-message-box__btns {
  padding: 16px 24px;
  border-top: 1px solid #ebeef5;
  background: #fafbfc;
}

.batch-operation-dialog .el-message-box__btns .el-button {
  padding: 10px 20px;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.2s;
}

.batch-operation-dialog .el-message-box__btns .el-button--default {
  border-color: #dcdfe6;
  color: #606266;
  background: #ffffff;
}

.batch-operation-dialog .el-message-box__btns .el-button--default:hover {
  color: #409eff;
  border-color: #c6e2ff;
  background: #ecf5ff;
}

.batch-operation-dialog .el-message-box__btns .el-button--primary {
  background: #409eff;
  border-color: #409eff;
}

.batch-operation-dialog .el-message-box__btns .el-button--primary:hover {
  background: #66b1ff;
  border-color: #66b1ff;
}

.batch-operation-dialog .el-message-box__btns .el-button--primary:active {
  background: #3a8ee6;
  border-color: #3a8ee6;
}
</style>

<style scoped lang="scss">
.defects-workspace {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 16px 24px;
  background: #f4f6fb;
  height: 100%;
  min-height: 0;
  overflow: hidden;
  position: relative;
}

.workspace-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  padding: 20px 24px;
  border-radius: 16px;
  background: linear-gradient(135deg, #ffffff 0%, #f8fbff 100%);
  box-shadow: 0 12px 32px rgba(36, 61, 99, 0.08);
  flex-shrink: 0;
}

.header-left .title-block h2 {
  margin: 0;
  font-size: 24px;
  font-weight: 600;
  color: #1f2a44;
}

.header-left .subtitle {
  margin: 6px 0 0;
  font-size: 14px;
  color: #607089;
}

.header-left {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1;
}

.header-right {
  display: flex;
  gap: 12px;
  align-items: center;
}

.project-selector-wrapper {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-right: 8px;
}

.project-label {
  font-size: 14px;
  color: #606266;
  font-weight: 500;
  white-space: nowrap;
}

.project-selector {
  min-width: 180px;
}

.view-switcher {
  background: #eef3ff;
  border-radius: 12px;
}

.refresh-button {
  display: flex;
  align-items: center;
  gap: 6px;
}

.create-button {
  display: flex;
  align-items: center;
  gap: 6px;
}

.workspace-main {
  margin-top: 0;
  display: flex;
  gap: 16px;
  flex: 1;
  min-height: 0;
  min-width: 0;
  overflow: hidden;
  height: 100%;
}

.filter-panel {
  width: 300px;
  position: relative;
  transition: width 0.24s ease, transform 0.24s ease;
  flex-shrink: 0;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  overflow: hidden;
}

.filter-panel.is-collapsed {
  width: 60px;
  transform: translateX(-12px);
}

.filter-panel.is-collapsed .filter-body {
  display: none;
}

.filter-panel.is-collapsed .filter-header {
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 12px 8px;
}

.filter-panel.is-collapsed .filter-header h3 {
  writing-mode: vertical-rl;
  margin: 0;
  letter-spacing: 4px;
}

.filter-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background: #ffffff;
  border-radius: 16px;
  box-shadow: 0 10px 24px rgba(33, 51, 96, 0.06);
  margin-bottom: 12px;
  flex-shrink: 0;
}

.filter-header h3 {
  margin: 0;
  font-size: 15px;
  color: #2b3c5c;
  font-weight: 600;
}

.collapse-btn {
  color: #4b5e89;
}

.filter-body {
  background: #ffffff;
  border-radius: 16px;
  box-shadow: 0 10px 24px rgba(33, 51, 96, 0.06);
  padding: 16px 18px;
  overflow-y: auto;
  overflow-x: hidden;
  flex: 1;
  min-height: 0;
  max-height: 100%;
  
  &::-webkit-scrollbar {
    width: 6px;
  }
  
  &::-webkit-scrollbar-thumb {
    background: #c1c1c1;
    border-radius: 3px;
    
    &:hover {
      background: #a8a8a8;
    }
  }
  
  &::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
  }
}

.workspace-content {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1;
  min-height: 0;
  min-width: 0;
  overflow: hidden;
}

.workspace-body {
  flex: 1;
  min-height: 0;
  min-width: 0;
  overflow: hidden;
  width: 100%;
  display: flex;
  flex-direction: column;
}

.fade-slide-enter-active,
.fade-slide-leave-active {
  transition: all 0.28s ease;
}

.fade-slide-enter-from,
.fade-slide-leave-to {
  opacity: 0;
  transform: translateY(12px) scale(0.99);
}
</style>
